package com.chatplus.application.service.auth.authentication.impl;


import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import com.chatplus.application.common.enumeration.AccountErrorCode;
import com.chatplus.application.common.enumeration.UserTypeEnum;
import com.chatplus.application.domain.entity.account.UserEntity;
import com.chatplus.application.domain.response.AccountLoginResponse;
import com.chatplus.application.service.account.UserService;
import com.chatplus.application.service.auth.authentication.AuthenticationProvider;
import com.chatplus.application.service.auth.authentication.AuthenticationToken;
import com.chatplus.application.service.auth.authentication.PasswordAuthenticationToken;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import static cn.hutool.core.lang.Assert.isTrue;
import static cn.hutool.core.lang.Assert.notBlank;

@Component
public class PasswordAuthenticationProvider implements AuthenticationProvider {

    private final UserService userService;

    public PasswordAuthenticationProvider(UserService userService) {
        this.userService = userService;
    }

    @Override
    public String getName() {
        return "账号密码认证";
    }

    @Override
    public AccountLoginResponse authenticate(AuthenticationToken authenticationToken) {
        UserEntity userEntity = userService.getByUsername((String) authenticationToken.getUserPrincipal());
        AccountLoginResponse userAccount = BeanUtil.copyProperties(userEntity, AccountLoginResponse.class);
        userAccount.setUserType(Boolean.TRUE.equals(userEntity.getAdmin()) ? UserTypeEnum.ADMIN_USER : UserTypeEnum.NORMAL_USER);
        checkAccountPassword(((PasswordAuthenticationToken) authenticationToken).getPassword(), userEntity.getPassword());
        AuthenticationProvider.checkAccountHasLocked(userAccount);
        return userAccount;
    }

    @Override
    public boolean supports(AuthenticationToken authenticationToken) {
        return authenticationToken instanceof PasswordAuthenticationToken passwordAuthenticationToken
                && StringUtils.isNotBlank((passwordAuthenticationToken.getPassword()));
    }


    private void checkAccountPassword(String plainPassword, String hashedPassword) {
        notBlank(plainPassword, AccountErrorCode.ACCOUNT_OR_PASSWORD_INVALID);
        notBlank(hashedPassword, AccountErrorCode.ACCOUNT_OR_PASSWORD_INVALID);
        // 兼容微信公众号的登录
        if (!plainPassword.equals(hashedPassword)) {
            isTrue(BCrypt.checkpw(plainPassword, hashedPassword), AccountErrorCode.ACCOUNT_OR_PASSWORD_INVALID);
        }
    }
}
